//#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include "li_list.h"

// int32_t li_count = 0;
int32_t init_list(Lily_List* list, uint32_t unit_size2, uint32_t init_cap)
{
	list->type_size = unit_size2;
	list->cap = 0;
	list->content = (char*)calloc(init_cap, unit_size2);

	if (list->content == NULL)
		return 1;
	list->cap = init_cap;
	list->count = 0;
	return 0;
}
Lily_List* new_list(uint32_t type, uint32_t init_cap)
{
	// li_count++;
	// static char tx[30];
	// sprintf(tx,"+>%d\n",li_count);
	// lily_out(tx);

	Lily_List* list = (Lily_List*)malloc(sizeof(Lily_List));

	if (list == NULL)
		return list;
	list->count = 0;
	list->type_size = type;
	list->content = (char*)calloc(init_cap, type);

	if (list->content == NULL)
		list->cap = 0;
	else
		list->cap = init_cap;

	return list;
}
Lily_List* copy_list(Li_List src)
{
	Lily_List* list = (Lily_List*)malloc(sizeof(Lily_List));
	if (list == NULL)
		return list;
	*list = *src;
	return list;
}

int32_t list_recap(Lily_List* list, uint32_t new_cap)
{
	void* p;
	p = realloc(list->content, new_cap * list->type_size);
	if (p == NULL)
	{
		return -1;
	}
	list->content = (char*)p;
	list->cap = new_cap;
	return 0;
}
int32_t list_add(Lily_List* list, void* c)
{
	if (!list)
		return -2;
	if (list->count >= list->cap)
	{
		if (list_recap(list, list->cap + 4) < 0)
		{
			if (list_recap(list, list->cap + 1) < 0)
				return -1;
		}
	}

	memcpy((char*)(list->content) + list->count * list->type_size, c, list->type_size);
	list->count++;
	return list->count - 1;
}
int32_t list_remove_at(Lily_List* list, uint32_t index)
{
	if (index >= list->count)
		return -1;
	char* i, * n, * p;
	list->count--;
	n = list->content + list->count * list->type_size;
	i = list->content + index * list->type_size;
	p = i + list->type_size;
	for (; i < n; i++, p++)
		*i = *p;
	// while (i < n) *(i++) = *(p++);
	return 0;
}
char list_item_equal(void* item_a, void* item_b, uint32_t type)
{
	int32_t i;
	char* item1 = (char*)item_a;
	char* item2 = (char*)item_b;
	for (i = 0; i < type; i++)
	{
		if (item1[i] != item2[i])
			return 0;
	}
	return 1;
}
int32_t list_remove(Lily_List* list, void* item)
{
	int32_t i;
	char* p = list->content;
	for (i = 0; i < list->count; i++, p += list->type_size)
		if (list_item_equal(item, p, list->type_size))
			break;
	if (i == list->count)
		return -1;
	list_remove_at(list, i);
	return 0;
}
int32_t list_find(Lily_List* list, void* item)
{
	int32_t i;
	char* p = list->content;
	for (i = 0; i < list->count; i++, p += list->type_size)
		if (list_item_equal(item, p, list->type_size))
			return i;
	return -1;
}

int32_t delete_list(Lily_List* list)
{
	if (list == NULL)
		return -1;
	if (list->content != NULL)
		free(list->content);
	free(list);
	return 0;
}
int32_t delete_list_t(Lily_List* list)
{
	if (list == NULL)
		return -1;
	if (list->content != NULL)
		free(list->content);
	return 0;
}
int32_t delete_list_recursively(Lily_List* list)
{
	if (list == NULL)
		return -1;
	if (list->content != NULL)
	{
		char** p = list_content(list, char*);
		for (int i = 0; i < list->count; i++)
		{
			free(p[i]);
		}
		free(list->content);
	}
	free(list);
	return 0;
}
// resize a list to save memory space
int32_t list_reduction(Li_List list)
{
	if (list->count == list->cap)
		return 0;
	int32_t used;
	if (list->count == 0)
	{
		used = list->type_size;
	}
	else
		used = list->type_size * list->count;
	void* p = realloc(list->content, used);
	if (p == NULL) //
		return -2;
	list->content = p;
	used = list->cap * list->type_size - used;
	list->cap = list->count;
	return used;
}
int32_t list_insert(Li_List list, void* c, int32_t at)
{
	if (list->count >= list->cap)
	{
		if (list_recap(list, list->cap + 4) < 0)
		{
			if (list_recap(list, list->cap + 1) < 0)
				return -1;
		}
	}

	int32_t n = list->count;
	int32_t i;
	for (i = n; i > at; i--)
	{
		void* pi;
		void* pi_1;
		pi = (char*)(list->content) + i * list->type_size;
		pi_1 = (char*)(list->content) + (i - 1) * list->type_size;
		memcpy(pi, pi_1, list->type_size); // p[i]=p[i-1]
	}
	list->count++;
	memcpy((char*)(list->content) + at * list->type_size, c, list->type_size); // p[at]=c
	return at;
}

#pragma region Stack
int32_t stack_push(Li_Stack list, void* c)
{
	return list_add(list, c);
}
int32_t stack_pop(Li_Stack list, void* dst_ptr)
{
	if (list->count <= 0)
		return -1;
	uint8_t *src = (uint8_t*)(list->content) + list->count * list->type_size;
	uint8_t* dst = (uint8_t*)dst_ptr;
	memcpy(dst, src, list->type_size);
	list->count--;
	return list->count;
}
int32_t stack_peek(Li_Stack list, void* dst_ptr)
{
	if (list->count <= 0)
		return -1;
	uint8_t* src = (uint8_t*)(list->content) + list->count * list->type_size;
	uint8_t* dst = (uint8_t*)dst_ptr;
	memcpy(dst, src, list->type_size);
	return list->count;
}
#pragma endregion

#pragma region li_string
// depracted
//  use new_string_by to creat sample string field
Li_String new_li_string_by(char* str)
{
	Li_String li_string = (Li_String)malloc(sizeof(Li_String_def));
	if (li_string == NULL)
		return NULL;
	int32_t n = strlen(str);
	li_string->str = (char*)malloc(n + 1);
	if (li_string->str == NULL)
	{
		free(li_string);

		return NULL;
	}
	strcpy(li_string->str, str);
	li_string->length = n;
	return li_string;
}
char* new_string_by(char* str)
{
	if (str == NULL)
		return NULL;
	int32_t n = strlen(str) + 1;
	void* p = malloc(n);
	if (p == NULL)
		return NULL;
	strcpy((char*)p, str);
	return (char*)p;
}

void delete_li_string(Li_String li)
{
	free(li->str);
	free(li);
}
int32_t assign_li_string(Li_String li, char* source)
{
	int32_t n = strlen(source);
	if (n > li->length)
	{
		void* p = realloc(li->str, n + 1);
		if (p == NULL)
		{
			return -1;
		}
		li->str = (char*)p;
	}
	strcpy(li->str, source);
	li->length = n;
	return n;
}
#pragma endregion